#ifndef __MY_LOOPER__
#define __MY_LOOPER__
#include "buffer.hpp"
#include <mutex>
#include <condition_variable>
#include <thread>
#include <functional>
#include <memory>
#include <atomic>

namespace wzh
{
    using Functor = std::function<void(Buffer &)>;
    enum class AsyncType
    {
        ASYNC_SAFE,
        ASYNC_UNSAFE
    };

    class AsyncLooper
    {
    public:
        using ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(const Functor &cb, AsyncType loop_type = AsyncType::ASYNC_SAFE)
            : _stop(false), _thread(std::thread(&AsyncLooper::threadEntry, this)), _callback(cb), _looper_type(loop_type)
        {
        }

        void stop()
        {
            _stop = true;
            _cond_con.notify_all(); // 唤醒所有线程
            _thread.join();
        }

        void push(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_looper_type == AsyncType::ASYNC_SAFE)
                _cond_pro.wait(lock, [&]()
                               { return _prod_buf.writeAbleSize() >= len; });
            _prod_buf.push(data, len);
            _cond_con.notify_one();
        }

    private:
        void threadEntry() // 线程入口函数
        {
            while (1)
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    if(_stop && _prod_buf.empty()) break;
                    _cond_con.wait(lock, [&]()
                                   { return _stop || !_prod_buf.empty(); });
                    _cons_buf.swap(_prod_buf);
                    if (_looper_type == AsyncType::ASYNC_SAFE)
                        _cond_pro.notify_all();
                }
                _callback(_cons_buf);
                _cons_buf.reset();
            }
        }

    private:
        Functor _callback;

    private:
        AsyncType _looper_type;
        std::atomic<bool> _stop;
        Buffer _prod_buf;
        Buffer _cons_buf;
        std::mutex _mutex;
        std::condition_variable _cond_pro;
        std::condition_variable _cond_con;
        std::thread _thread;
    };
}

#endif